<template>
  <div class="pf-flow-prop-task-listeners" id="js-properties-panel-custom">
    <el-table :data="elementListenersList" size="mini" border>
      <el-table-column label="序号" width="50px" type="index" />
      <el-table-column label="事件类型" min-width="100px" prop="event" />
      <el-table-column
        label="监听器类型"
        min-width="100px"
        show-overflow-tooltip
        :formatter="row => listenerTypeObject[row.listenerType]"
      />
      <el-table-column label="操作" width="90px">
        <template v-slot="{ row, $index }">
          <el-button size="mini" link type="primary" @click="openListenerForm(row, $index)"
            >编辑</el-button
          >
          <el-divider direction="vertical" />
          <el-button
            size="mini"
            link
            type="primary"
            style="color: #ff4d4f"
            @click="removeListener(row, $index)"
            >移除</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <div class="element-drawer__button">
      <el-button size="mini" type="primary" icon="el-icon-plus" @click="openListenerForm(null, 0)"
        >添加监听器</el-button
      >
    </div>

    <!-- 监听器 编辑/创建 部分 -->
    <el-drawer
      v-model="listenerFormModelVisible"
      title="执行监听器"
      :size="'500px'"
      append-to-body
      destroy-on-close
    >
      <pf-form
        :config="listenerFormConfig"
        :model="listenerForm"
        ref="listenerFormRef"
        @changeEvent="listenerFormChange"
      ></pf-form>
      <el-divider />
      <p class="listener-filed__title">
        <span><i class="el-icon-menu"></i>注入字段：</span>
        <el-button size="mini" type="primary" @click="openListenerFieldForm(null, 0)"
          >添加字段</el-button
        >
      </p>
      <el-table
        :data="fieldsListOfListener"
        size="mini"
        max-height="240"
        border
        fit
        style="flex: none"
      >
        <el-table-column label="序号" width="50px" type="index" />
        <el-table-column label="字段名称" min-width="100px" prop="name" />
        <el-table-column
          label="字段类型"
          min-width="80px"
          show-overflow-tooltip
          :formatter="row => fieldTypeObject[row.fieldType]"
        />
        <el-table-column
          label="字段值/表达式"
          min-width="100px"
          show-overflow-tooltip
          :formatter="row => row.string || row.expression"
        />
        <el-table-column label="操作" width="100px">
          <template v-slot="{ row, $index }">
            <el-button size="mini" link type="primary" @click="openListenerFieldForm(row, $index)"
              >编辑</el-button
            >
            <el-divider direction="vertical" />
            <el-button
              size="mini"
              link
              style="color: #ff4d4f"
              @click="removeListenerField(row, $index)"
              >移除</el-button
            >
          </template>
        </el-table-column>
      </el-table>

      <div class="element-drawer__button">
        <el-button size="mini" @click="listenerFormModelVisible = false">取 消</el-button>
        <el-button size="mini" type="primary" @click="saveListenerConfig">保 存</el-button>
      </div>
    </el-drawer>

    <!-- 注入西段 编辑/创建 部分 -->
    <el-dialog
      title="字段配置"
      v-model="listenerFieldFormModelVisible"
      width="600px"
      append-to-body
      destroy-on-close
    >
      <pf-form
        :model="listenerFieldForm"
        :config="listenerFieldFormConfig"
        ref="listenerFieldFormRef"
        @changeEvent="listenerFieldFormChange"
      >
      </pf-form>
      <template v-slot:footer>
        <el-button size="mini" @click="listenerFieldFormModelVisible = false">取 消</el-button>
        <el-button size="mini" type="primary" @click="saveListenerFiled">确 定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script lang="ts">
import { defineComponent, nextTick, onMounted, ref, Ref, toRefs, watch } from 'vue';
import { FormModel } from 'pf-component';
import {
  buildExListenerField,
  buildExTaskListener
} from '@/views/page-config/flow/custom-properties/form-data';
import { CamundaTaskName, modeler } from '@/views/page-config/flow/flow-modeler';
import {
  fieldType,
  initListenerForm,
  initListenerType,
  listenerType
} from '@/views/page-config/flow/custom-properties/listener-utils';
import { ElMessageBox } from 'element-plus';

export default defineComponent({
  name: 'UserTaskListeners',
  props: ['id'],
  setup(props) {
    const id: Ref = toRefs(props).id;
    const elementListenersList: Ref<string[]> = ref([]); // 监听器列表
    const fieldsListOfListener: Ref<string[]> = ref([]);

    const listenerForm: Ref = ref({}); // 监听器详情表单
    const listenerFormConfig: Ref<FormModel> = ref(buildExTaskListener()); // 监听器详情表单
    const listenerFormModelVisible: Ref = ref(false); // 监听器 编辑 侧边栏显示状态
    const listenerFormRef: Ref = ref(null);
    const listenerFieldForm: Ref = ref({}); // 监听器 注入字段 详情表单
    const listenerFieldFormConfig: Ref<FormModel> = ref(buildExListenerField()); // 监听器 注入字段 详情表单
    const listenerFieldFormModelVisible: Ref = ref(false); // 监听器 注入字段表单弹窗 显示状态
    const listenerFieldFormRef: Ref = ref(null);

    let editingListenerIndex = -1; // 监听器所在下标，-1 为新增
    let editingListenerFieldIndex = -1; // 字段所在下标，-1 为新增

    let bpmnElementListeners: any[] = [];
    let otherExtensionList: any[] = [];

    const resetListenersList = () => {
      otherExtensionList = [];
      bpmnElementListeners =
        modeler
          .getActiveElement()
          ?.businessObject?.extensionElements?.values?.filter(
            (ex: any) => ex.$type === CamundaTaskName.taskListener
          ) ?? [];
      elementListenersList.value = bpmnElementListeners.map(listener => initListenerType(listener));
    };
    // 打开 监听器详情 侧边栏
    const openListenerForm = (listener: any, index: number) => {
      if (listener) {
        listenerForm.value = initListenerForm(listener);
        editingListenerIndex = index;
      } else {
        listenerForm.value = {};
        editingListenerIndex = -1; // 标记为新增
      }
      if (listener && listener.fields) {
        fieldsListOfListener.value = listener.fields.map((field: any) => ({
          ...field,
          fieldType: field.string ? 'string' : 'expression'
        }));
      } else {
        fieldsListOfListener.value = [];
        listenerForm.value.fields = [];
      }
      // 打开侧边栏并清楚验证状态
      listenerFormModelVisible.value = true;
      nextTick(() => {
        if (listenerFormRef.value) listenerFormRef.value.clearValidate();
      });
    };
    // 打开监听器字段编辑弹窗
    const openListenerFieldForm = (field: any, index: number) => {
      listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {};
      editingListenerFieldIndex = field ? index : -1;
      listenerFieldFormModelVisible.value = true;
      nextTick(() => {
        if (listenerFieldFormRef.value) listenerFieldFormRef.value.clearValidate();
      });
    };
    // 保存监听器注入字段
    const saveListenerFiled = async () => {
      const validateStatus = await listenerFieldFormRef.value.validate();
      if (!validateStatus) {
        return; // 验证不通过直接返回
      }
      if (editingListenerFieldIndex === -1) {
        fieldsListOfListener.value.push(listenerFieldForm.value);
        listenerForm.value.fields.push(listenerFieldForm.value);
      } else {
        fieldsListOfListener.value.splice(editingListenerFieldIndex, 1, listenerFieldForm.value);
        listenerForm.value.fields.splice(editingListenerFieldIndex, 1, listenerFieldForm.value);
      }
      listenerFieldFormModelVisible.value = false;
      // await nextTick(() => (listenerFieldForm.value = {}));
      await nextTick();
      listenerFieldForm.value = {};
    };

    // 移除监听器字段
    const removeListenerField = (field: any, index: number) => {
      ElMessageBox.confirm('确认移除该字段吗？', '提示', {
        confirmButtonText: '确 认',
        cancelButtonText: '取 消'
      })
        .then(() => {
          fieldsListOfListener.value.splice(index, 1);
          listenerForm.value.fields.splice(index, 1);
        })
        .catch(() => console.info('操作取消'));
    };
    // 移除监听器
    const removeListener = (listener: any, index: number) => {
      ElMessageBox.confirm('确认移除该监听器吗？', '提示', {
        confirmButtonText: '确 认',
        cancelButtonText: '取 消'
      })
        .then(() => {
          bpmnElementListeners.splice(index, 1);
          elementListenersList.value.splice(index, 1);
          modeler.updateActiveElementExtensions(otherExtensionList.concat(bpmnElementListeners));
        })
        .catch(() => console.info('操作取消'));
    };
    // 保存监听器配置
    const saveListenerConfig = async () => {
      const validateStatus = await listenerFormRef.value.validate();
      if (!validateStatus) return; // 验证不通过直接返回
      const listenerObject = modeler.createListenerObject(listenerForm.value, true);
      if (editingListenerIndex === -1) {
        bpmnElementListeners.push(listenerObject);
        elementListenersList.value.push(listenerForm.value);
      } else {
        bpmnElementListeners.splice(editingListenerIndex, 1, listenerObject);
        elementListenersList.value.splice(editingListenerIndex, 1, listenerForm.value);
      }
      // 保存其他配置
      otherExtensionList =
        modeler
          .getActiveElement()
          .businessObject?.extensionElements?.values?.filter(
            (ex: any) => ex.$type !== CamundaTaskName.taskListener
          ) ?? [];
      modeler.updateActiveElementExtensions(otherExtensionList.concat(bpmnElementListeners));
      // 4. 隐藏侧边栏
      listenerFormModelVisible.value = false;
      listenerForm.value = {};
    };
    const listenerFieldFormChange = (newV: any, prop: string) => {
      if (prop === 'fieldType') {
        if (newV === 'string') {
          listenerFieldFormConfig.value.setHiddenWithRequired('string', false, true);
          listenerFieldFormConfig.value.setHiddenWithRequired('expression', true, false);
        } else if (newV === 'expression') {
          listenerFieldFormConfig.value.setHiddenWithRequired('expression', false, true);
          listenerFieldFormConfig.value.setHiddenWithRequired('string', true, false);
        }
      }
    };
    const listenerFormChange = (newV: any, prop: string) => {
      if (prop === 'event') {
        const fields: string[] = ['eventDefinitionType', 'eventTimeDefinitions'];
        if (newV === 'timeout') {
          listenerFormConfig.value.setHiddenWithRequired(fields, false, true);
        } else {
          listenerFormConfig.value.setHiddenWithRequired(fields, true, false);
        }
      } else if (prop === 'eventDefinitionType') {
        if (newV === '-1') {
          listenerFormConfig.value.setHiddenWithRequired('eventTimeDefinitions', true, false);
        } else {
          listenerFormConfig.value.setHiddenWithRequired('eventTimeDefinitions', false, true);
        }
      } else if (prop === 'listenerType') {
        const fields: string[] = [
            'class',
            'expression',
            'delegateExpression',
            'scriptFormat',
            'scriptType',
            'value',
            'resource'
          ],
          show: string[] = [],
          hidden: string[] = [];
        if (newV === 'classListener') {
          fields.forEach(f => {
            if (f === 'class') {
              show.push(f);
            } else {
              hidden.push(f);
            }
          });
        } else if (newV === 'expressionListener') {
          fields.forEach(f => {
            if (f === 'expression') {
              show.push(f);
            } else {
              hidden.push(f);
            }
          });
        } else if (newV === 'delegateExpressionListener') {
          fields.forEach(f => {
            if (f === 'delegateExpression') {
              show.push(f);
            } else {
              hidden.push(f);
            }
          });
        } else if (newV === 'scriptListener') {
          fields.forEach(f => {
            if (f === 'scriptFormat' || f === 'scriptType' || f === 'value' || f === 'resource') {
              show.push(f);
            } else {
              hidden.push(f);
            }
          });
        }
        show.forEach(f => listenerFormConfig.value.setHiddenWithRequired(f, false, true));
        hidden.forEach(f => listenerFormConfig.value.setHiddenWithRequired(f, true, false));
      } else if (prop === 'scriptType') {
        if (newV === 'inlineScript') {
          listenerFormConfig.value.setHiddenWithRequired('value', false, true);
          listenerFormConfig.value.setHiddenWithRequired('resource', true, false);
        } else if (newV === 'externalScript') {
          listenerFormConfig.value.setHiddenWithRequired('resource', false, true);
          listenerFormConfig.value.setHiddenWithRequired('value', true, false);
        }
      }
    };
    onMounted(() => {});
    watch(
      id,
      () => {
        nextTick(() => {
          resetListenersList();
        });
      },
      { immediate: true }
    );
    return {
      listenerFieldForm,
      listenerFieldFormRef,
      listenerFieldFormConfig,
      listenerFieldFormModelVisible,
      listenerForm,
      listenerFormRef,
      listenerFormConfig,
      listenerFormChange,
      listenerFormModelVisible,

      elementListenersList,
      fieldsListOfListener,

      removeListenerField,
      removeListener,
      saveListenerConfig,
      saveListenerFiled,
      openListenerForm,
      openListenerFieldForm,
      listenerFieldFormChange,

      listenerTypeObject: listenerType,
      fieldTypeObject: fieldType
    };
  }
});
</script>
<style scoped lang="scss">
.#{$prefix} {
}
</style>
